<template>
  <div ref="editorContainer" :style="{ width: '100%', height: editorHeight + 'px' }">
    <!--EditorHeader-->
    <div class="editor-header">
      <div class='leftBar' style="float: left">
        <el-select
            class="custom-select"
            v-model="themeChoose"
            placeholder="请选择主题"
            size="mini">
          <el-option
              v-for="item in themes"
              :key="item"
              :label="item"
              :value="item">
          </el-option>
        </el-select>
      </div>
      <div class="actionBarContainer rightBar" style="float: right;align-content: center">
        <ActionBar
            :editorValue="editorValue"
            :setValue="setValue"
            :changeHideStatus="changeHideStatus"
            :changeFoldStatus="changeFoldStatus"
            :copyValue="copyValue"
            :isCopied="isCopied"
            :setDialect="setDialect"
            :run-code="runCode"
        />
      </div>
    </div>
    <!--EditorBody-->
    <div class="editorBody" v-show="isShowEditor">
      <div ref="editor" id="editor"></div>
    </div>
    <!--EditorResult -->
    <div class="resultBody">
      <Result
          :metadata="result.metaData"
          :result=result
          :code="editorValue"
      />
    </div>
  </div>
</template>

<script>
import ace from 'ace-builds/src-noconflict/ace';
import 'ace-builds/src-noconflict/theme-monokai';
import 'ace-builds/src-noconflict/theme-chrome';
import 'ace-builds/src-noconflict/theme-github';
import 'ace-builds/src-noconflict/theme-kuroir';
import 'ace-builds/src-noconflict/theme-twilight';
import 'ace-builds/src-noconflict/theme-xcode';
import 'ace-builds/src-noconflict/theme-textmate';
import 'ace-builds/src-noconflict/theme-solarized_dark';
import 'ace-builds/src-noconflict/theme-dracula';
import 'ace-builds/src-noconflict/mode-javascript';
import 'ace-builds/src-noconflict/mode-mysql';
import 'ace-builds/src-noconflict/mode-sql';
import ActionBar from "@/components/ActionBar";
import Result from "@/components/Result";
import 'ace-builds/src-noconflict/ext-language_tools';
import SqlFoldMode from "@/components/SqlFoldMode";
import $ from 'jquery';
import 'jquery-contextmenu/dist/jquery.contextMenu.min.css';
import 'jquery-contextmenu/dist/jquery.contextMenu.min.js';
import {Parser} from 'node-sql-parser';
import '@/components/mode-hive'
import executeApi from '@/api/code-executor'
import metaApi from '@/api/table-meta'

export default {
  name: 'CodeEditor',
  components: {ActionBar, Result},
  props: {
    content: {
      type: String,
      default: '',
    },
    mode: {
      type: String,
      // default: 'javascript',
      default: 'mysql',
    },
    theme: {
      type: String,
      default: 'monokai',
    },
    minLines: {
      type: Number,
      default: 2,
    },
    maxLines: {
      type: Number,
      default: 30,
    },
    placeholder: {
      type: String,
      default: '请输如你的sql代码',
    },
  },
  data() {
    return {
      schemas: [],
      tables: [],
      columns: [],
      executeParam: {code: '', executeType: 'Mysql'},
      sql: '',
      result: {executorType: '', metaData: {}, data: []},
      parsedSQL: null,
      dialect: 'mysql',
      editorHeight: 30, // 初始高度，稍后会根据内容调整
      isShowEditor: true,  // 当前折叠状态
      isFold: false,
      // code: 'SELECT\n' +
      //     '  name,\n' +
      //     '  age,\n' +
      //     '  sex,\n' +
      //     '  sum(price) / sum(value) AS single,\n' +
      //     '  CASE\n' +
      //     '    WHEN user_info.user_type IS NULL\n' +
      //     '    OR user_info.user_type = \'\' THEN CASE\n' +
      //     '      WHEN nu.buyer_id IS NOT NULL THEN \'new\'\n' +
      //     '      ELSE \'dormant\'\n' +
      //     '    END\n' +
      //     '    ELSE user_info.user_type\n' +
      //     '  END AS user_type\n' +
      //     'FROM\n' +
      //     '  (\n' +
      //     '    SELECT\n' +
      //     '      *\n' +
      //     '    FROM\n' +
      //     '      (\n' +
      //     '        SELECT\n' +
      //     '          *\n' +
      //     '        FROM\n' +
      //     '          user\n' +
      //     '      ) a\n' +
      //     '    WHERE\n' +
      //     '      a = 1\n' +
      //     '  )\n' +
      //     'WHERE\n' +
      //     '  aaa = 1\n' +
      //     '  AND sex > 2',
      code: 'select * from guli_edu.edu_teacher',
      editorValue: '',
      isCopied: false,
      themeChoose: 'monokai',
      themes: ['monokai', 'github', 'kuroir', 'twilight', 'xcode',
        'textmate', 'solarized_dark', 'chrome', 'dracula'],
      // 模拟的本地数据库表名
      mockDatabaseTables: {
        "db1": ["table1", "table2", "table3"],
        "db2": ["table4", "table5", "table6"]
      },
      fieldCompletion: [],
      tableAsInfo: {},
    };
  },
  watch: {
    themeChoose(newValue) {
      this.editor.setTheme(`ace/theme/${newValue}`);
    },
    content(newValue) {
      if (this.editor.getValue() !== newValue) {
        this.editor.setValue(newValue, -1);
      }
      this.adjustHeight();
    },
    mode(newValue) {
      this.editor.session.setMode(`ace/mode/${newValue}`);
    },
    theme(newValue) {
      this.editor.setTheme(`ace/theme/${newValue}`);
    },
    dialect(newValue) {
      this.validateSQL();
      const supportMode = ['mysql', 'sql', 'hive']
      if (supportMode.includes(newValue)) {
        this.applyFoldRules(newValue)
      }
    },
    placeholder(newValue) {
      this.editor.setOption('placeholder', newValue);
    },
  },
  mounted() {
    this.getSchemaCompletion();
    this.initEditor();
  },
  beforeDestroy() {
    this.editor.destroy();
    this.fieldCompletion = []
  },
  methods: {
    async getSchemaCompletion() {
      try {
        this.schemas = await metaApi.schema() || [];  // 假设 res.data 是你要赋值给 this.schemas 的数据
        const dbSchemaCompletions = this.schemas.map(dbName => {
          return {
            caption: dbName,
            value: dbName,
            score: 10,
            meta: `database|${this.dialect}`,
            docHTML: `<b>${dbName}</b>: A table in the ${this.dialect}.`
          }
        });
        this.addCompleter({
          getCompletions: (editor, session, pos, prefix, callback) => {
            callback(null, dbSchemaCompletions);
          }
        });
      } catch (error) {
        console.error('Error fetching schema:', error);
      }
    },
    async getTableCompletion(schema) {
      try {
        this.tables = await metaApi.table({schema}) || [];
        const tableCompletions = this.tables.map(tableName => ({
          caption: tableName,
          value: tableName,
          score: 100,
          meta: `table|${schema}`,
          docHTML: `<b>${tableName}</b>: A table in the ${schema}.`
        }));
        this.addCompleter({
          getCompletions: (editor, session, pos, prefix, callback) => {
            callback(null, tableCompletions);
          }
        });
      } catch (error) {
        console.error('Error fetching tables:', error);
      }
    },
    async getFieldCompletion(schema, table) {
      try {
        this.columns = await metaApi.column({schema, table}) || [];
        const tableAsName = this.tableAsInfo[table]
        const fieldCompletions = this.columns.map(column => ({
          caption: !tableAsName ? column.columnName : tableAsName + "." + column.columnName,
          value: !tableAsName ? column.columnName : tableAsName + "." + column.columnName,
          score: 500,
          meta: `field|${table}`,
          docHTML: `<b>${column.columnName}</b>: A field in the ${schema}.${table} <br>`+
                   `${column.columnType} columnComent: ${!column.columnComment ? '' : column.columnComment}`
        }));
        this.addCompleter({
          getCompletions: (editor, session, pos, prefix, callback) => {
            callback(null, fieldCompletions);
          }
        });
      } catch (error) {
        console.error('Error fetching fields:', error);
      }
    },

    addCompleter(completer) {
      ace.require("ace/ext/language_tools").addCompleter(completer);
    },
    removeAllCompleters() {
      const langTools = ace.require('ace/ext/language_tools');
      langTools.setCompleters([]);
    },
    runCode() {
      this.executeParam.code = this.editorValue;
      this.executeParam.executeType = this.mode.charAt(0).toUpperCase() + this.mode.slice(1);
      console.log("执行参数:" + JSON.stringify(this.executeParam))
      executeApi.execute(this.executeParam).then(res => {
        this.result = res
        console.log("显示结果:" + JSON.stringify(this.result))
      })

    },
    applyMetaCompleter() {
      const fieldCompleter = {
        // id: "fieldCompleter",
        getCompletions: (editor, session, pos, prefix, callback) => {
          var completions = [
            {
              caption: "test_user_name",
              value: "test_user_name",
              meta: "Field",
              score: 10,
              // description: "The user's name",
              docHTML: "<b>user_name</b>: The name of the user in the database.",
              // className: "fas fa-user",
              // tooltip: "This is the user's name field"
            },
            {
              caption: "user_email",
              value: "user_email",
              meta: "Field",
              score: 10,
              description: "The user's email",
              docHTML: "<b>user_email</b>: The email address of the user in the database.",
              // className: "fas fa-envelope",
              tooltip: "This is the user's email field"
            },
            {
              caption: "SELECT",
              value: "SELECT",
              meta: "Keyword",
              score: 10,
              description: "SQL SELECT statement",
              docHTML: "<b>SELECT</b>: SQL statement to select data from a database.",
              // className: "fas fa-database",
              tooltip: "This is the SELECT keyword"
            },
            {
              caption: "FROM",
              value: "FROM",
              meta: "Keyword",
              score: 10,
              description: "SQL FROM clause",
              docHTML: "<b>FROM</b>: SQL clause to specify the table to query data from.",
              // className: "fas fa-table",
              tooltip: "This is the FROM keyword"
            },
            {
              caption: "addEventListener",
              value: "element.addEventListener('event', function() {\n\t// code\n});",
              meta: "function"
            },
            {
              caption: "ddone",
              value: "会当凌绝顶,一层五开之径",
              meta: "模板"
            }
          ];
          // 模拟的本地数据库表名
          const mockDatabaseTables = {
            "db1": ["table1", "table2", "table3"],
            "db2": ["table4", "table5", "table6"]
          };
          const mockTableFields = {
            "table1": ["id1", "name1", "age1"],
            "table2": ["id2", "name2", "age2"],
            "table3": ["id3", "name3", "age3"],
            "table4": ["id4", "name4", "age4"],
            "table5": ["id5", "name5", "age5"],
            "table6": ["id6", "name6", "age6"]
          }
          // 获取用户输入的数据库名
          const cursorPosition = editor.getCursorPosition();
          const currentLine = session.getLine(cursorPosition.row);

          let commonCompletion = completions.map(function (c) {
            return {
              caption: c.caption,
              value: c.value,
              meta: c.meta,
              score: c.score,
              docHTML: c.docHTML
            };
          })
          // 如果之前字段已经缓存了 则这次直接继承
          commonCompletion = [...this.fieldCompletion, ...commonCompletion]

          // 设置数据库提示
          const dbSchemaCompletions = this.schemas.map(dbName => {
            console.log(dbName)
            return {
              caption: dbName,
              value: dbName,
              score: 10,
              meta: "database",
              docHTML: `<b>${dbName}</b>: A table in the ${this.dialect}.`
            }
          });
          console.log(dbSchemaCompletions);
          commonCompletion = [...dbSchemaCompletions, ...commonCompletion]

          // 匹配形如 dbName. 的模式 设置数据表提示
          const dbNameMatch = currentLine.match(/(\w+)\./);
          if (dbNameMatch) {
            const dbName = dbNameMatch[1]; // 提取数据库名称
            // 从本地模拟数据中获取表名
            const tables = mockDatabaseTables[dbName] || [];
            let tableCompletions = tables.map(tableName => ({
              caption: tableName,
              value: tableName,
              score: 20,
              meta: "table",
              docHTML: `<b>${tableName}</b>: A table in the ${dbName}.`
            }));
            commonCompletion = [...tableCompletions, ...commonCompletion]
          }
          // 匹配形如 dbName.tableName 的模式 设置字段提示
          const tableFieldMatch = currentLine.match(/(\w+)\.(\w+)/);
          if (tableFieldMatch) {

            const tableName = tableFieldMatch[2]; // 提取表名称
            const tableAsName = this.tableAsInfo[tableName]
            // 从本地模拟数据中获取字段
            const fields = mockTableFields[tableName] || [];
            this.lineFieldCompletions = fields.map(fieldName => ({
              caption: !tableAsName ? fieldName : tableAsName + "." + fieldName,
              value: !tableAsName ? fieldName : tableAsName + "." + fieldName,
              score: 30,
              meta: "field",
              docHTML: `<b>${fieldName}</b>: A field in the ${tableName} table.`
            }));
            this.fieldCompletion = [...this.lineFieldCompletions, ...this.fieldCompletion];
            commonCompletion = [...this.fieldCompletion, ...commonCompletion];
          }
          callback(null, commonCompletion);
        }
      };
      // 将自定义补全器添加到编辑器
      ace.require("ace/ext/language_tools").addCompleter(fieldCompleter);
    },
    initEditor() {
      this.editor = ace.edit(this.$refs.editor);
      this.editor.setTheme(`ace/theme/${this.theme}`);
      // this.editor.session.setMode(`ace/mode/${this.mode}`);
      this.editor.session.setMode(`ace/mode/${this.mode}`);
      this.editor.setValue(this.code, -1);
      // 设置最小和最大行数
      // 设置是否显示打印边界线
      this.editor.setShowPrintMargin(false);
      this.editor.setOptions({
        minLines: this.minLines,
        maxLines: this.maxLines,
        placeholder: this.placeholder,
        enableBasicAutocompletion: true, // 启用基本自动补全
        enableSnippets: true, // 启用代码片段
        enableLiveAutocompletion: true, // 启用实时自动补全
        fontSize: 16,
        showFoldWidgets: true,  // 显示折叠按钮
        foldStyle: "markbegin"
      });
      this.editorValue = this.code
      this.editor.on('change', () => {
        const newValue = this.editor.getValue();
        this.editorValue = newValue;
        this.$emit('update:content', newValue);
        this.$emit('input', newValue);
        this.adjustHeight();
        this.validateSQL();
        this.updateTableComplete(this.editor);
      });
      this.applyFoldRules(this.mode);
      // 初始化菜单
      this.initContextMenu();
      // // 添加自动补全
      // this.applyMetaCompleter();
    },
    updateTableComplete(editor) {
      const cursorPosition = editor.getCursorPosition();
      const currentLine = editor.session.getLine(cursorPosition.row);
      const cursorChar = currentLine.charAt(cursorPosition.column);
      if (cursorChar === "\.") {
        // 手动触发自动补全提示
        setTimeout(() => {
          editor.execCommand("startAutocomplete");
        }, 0);
      } else {
        if (editor.completer) {
          editor.completer.detach();
        }
      }
      // 匹配形如 dbName. 的模式 设置数据表提示
      const dbNameMatch = currentLine.match(/(\w+)\./);
      if (dbNameMatch) {
        const dbName = dbNameMatch[1]; // 提取数据库名称
        this.getTableCompletion(dbName)
      }

      // 匹配形如 dbName.tableName 的模式 设置字段提示
      const tableFieldMatch = currentLine.match(/(\w+)\.(\w+)/);
      if (tableFieldMatch) {
        const dbName = dbNameMatch[1]; // 提取数据库名称
        const tableName = tableFieldMatch[2]; // 提取表名称
        const tableAsName = this.tableAsInfo[tableName]
        this.getFieldCompletion(dbName, tableName, tableAsName)
      }
    },
    validateSQL() {
      const parser = new Parser();
      let sql = this.editor.getValue();
      // 替换 SQL 末尾的分号
      sql = sql.replace(/;\s*$/, '');
      try {
        const astifyAst = parser.astify(sql, {database: this.dialect}); // 尝试将 SQL 转换为 AST
        astifyAst.from.forEach(item => {
          this.tableAsInfo[item.table] = item.as
        })
        this.clearError();
      } catch (error) {
        this.showError(error.message, error.location);
      }
    },
    setDialect(dialect) {
      this.dialect = dialect
    },
    clearError() {
      this.editor.getSession().clearAnnotations();
      this.error = null;
    },
    showError(message, location) {
      const editorSession = this.editor.getSession();
      const annotations = [{
        row: location ? location.start.line - 1 : 0, // Ace Editor 行号从 0 开始
        column: location ? location.start.column : 0,
        text: message,
        type: 'error'
      }];
      this.editor.getSession().setAnnotations(annotations);
      this.error = message;
    },
    undo() {
      this.editor.undo();
    },
    adjustHeight() {
      if (this.editor) {
        // 获取行高和当前文档行数
        const lineHeight = this.editor.renderer.lineHeight;
        const rowCount = this.editor.session.getLength();

        // 计算编辑器高度
        let newHeight = lineHeight * rowCount;

        // 限制高度在 minLines 和 maxLines 之间
        newHeight = Math.max(newHeight, lineHeight * this.minLines);
        newHeight = Math.min(newHeight, lineHeight * this.maxLines);

        // 更新编辑器高度
        this.editorHeight = newHeight;
        this.editor.resize();
      }
    },
    setValue(value) {
      this.editor.setValue(value, -1);
    },
    changeHideStatus() {
      this.isShowEditor = !this.isShowEditor;
    },
    copyValue() {
      const codeToCopy = this.editor.getSelectedText() || this.editorValue
      this.editor.clearSelection();
      if (navigator.clipboard) {
        navigator.clipboard.writeText(codeToCopy)
            .then(() => {
              this.isCopied = true;
              setTimeout(() => {
                this.isCopied = false;
              }, 2000);
            })
            .catch(err => {
              console.error('Failed to copy: ', err);
            });
      } else {
        // 备用方案
        const textArea = document.createElement('textarea');
        textArea.value = codeToCopy;
        document.body.appendChild(textArea);
        textArea.select();
        try {
          document.execCommand('copy');
          this.isCopied = true;
          setTimeout(() => {
            this.isCopied = false;
          }, 2000);
        } catch (err) {
          console.error('Fallback: Oops, unable to copy', err);
        }
        document.body.removeChild(textArea);
      }
    },
    changeFoldStatus() {
      if (this.isFold) {
        this.editor.session.foldAll()
      } else {
        this.editor.session.unfold()
      }
      this.isFold = !this.isFold
    },
    applyFoldRules(mode) {
      // 设置自定义折叠规则
      const SqlMode = ace.require(`ace/mode/${mode}`).Mode;
      const sqlMode = new SqlMode();
      sqlMode.foldingRules = new SqlFoldMode();
      this.editor.session.setMode(sqlMode);
    },
    initContextMenu() {
      // 创建右键菜单
      $.contextMenu({
        selector: '#editor',
        callback: (key, options) => {
          switch (key) {
            case 'copy':
              this.copyValue();
              break;
            case 'clear':
              this.setValue('')
              break;
            case 'undo':
              this.undo();
              break;
            case 'execute':
              executeCode();
              break;
          }
        },
        items: {
          "copy": {name: "Copy", icon: "copy"},
          "clear": {name: "Clear", icon: "delete"},
          "execute": {name: "Execute", icon: "fas fa-play"},
          'undo': {name: 'Undo', icon: "fas fa-undo"},
          "sep1": "---------",
          "quit": {
            name: "Quit", icon: function () {
              return 'context-menu-icon context-menu-icon-quit';
            }
          }
        }
      });

      // 处理执行代码逻辑
      const executeCode = () => {
        const code = this.editorValue
        try {
          console.log(code)
        } catch (e) {
          console.error("Execution error: ", e);
        }
      }
      // 防止 Ace Editor 默认的右键菜单弹出
      this.editor.container.addEventListener('contextmenu', function (event) {
        event.preventDefault();
      });
    }
  },
};
</script>

<style scoped>
/* 设置编辑器容器的最小高度，以防止编辑器在内容很少时塌陷 */
#editorContainer {
  min-height: 100px;
}

.editor-header {
  background-color: #7F83F7;
  color: #ccc;
  padding: 8px 12px;
  font-size: 14px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  position: relative;
  margin-top: 20px;
}

.editor-header .themeSelector {
  background-color: #7f97f7;
  font-weight: bold;
  color: red;
}

.editor-header span {
  font-size: 16px;
}

.actionBarContainer {
  margin-right: 4px;
}

/* 自定义 el-select 和 el-option 样式 */
.editor-header .custom-select >>> .el-input__inner {
  color: white; /* 字体颜色 */
  background-color: #2048ae; /* 背景颜色 */
  font-size: 16px;
}

.editor-header.custom-select >>> .el-select-dropdown__item.selected {
  background-color: #7f97f7 !important; /* 选中项背景颜色 */
  color: #ffffff !important; /* 选中项字体颜色 */
}

.editor-header .custom-select >>> .el-select-dropdown__item:hover {
  background-color: #555555 !important; /* 悬停项背景颜色 */
  color: #7f97f7 !important; /* 悬停项字体颜色 */
}

.editor-header .custom-select >>> .el-select-dropdown__item {
  background-color: #444444; /* 默认项背景颜色 */
  color: #ffffff; /* 默认项字体颜色 */
}

</style>
